package com.ljk.util.jackson;

import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.ljk.util.string.StringUtil;

import java.util.Map;

/**
 * XML 工具类，提供 XML 与 Java 对象之间的转换功能。
 */
public class XmlUtil {
    private XmlUtil() {
    }

    private static final XmlMapper MAPPER;

    static {
        MAPPER = new XmlMapper();
    }

    /**
     * 将 XML 字符串转换为 JSON 字符串。注意,转为JSON所有字段都会转成字符串，所以如果字段是数字，会变成字符串。
     *
     * @param xml 要转换的 XML 字符串
     * @return 转换后的 JSON 字符串，如果输入为空则返回 null
     */
    public static String toJson(String xml) {
        if (StringUtil.isEmpty(xml)) {
            return null;
        }
        return JsonUtil.toJson(parseXml(xml));
    }

    /**
     * 将 XML 字符串解析为指定类型的 Java 对象。
     *
     * @param xml 要解析的 XML 字符串
     * @param clz 目标 Java 对象的类类型
     * @param <T> 目标 Java 对象的类型
     * @return 解析后的 Java 对象
     * @throws RuntimeException 如果解析失败
     */
    public static <T> T parseXml(String xml, Class<T> clz) {
        try {
            return MAPPER.readValue(xml, clz);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(String.format("解析xml失败,原文[%s]", xml), e);
        }
    }

    /**
     * 将 XML 字符串解析为指定类型的 Java 对象，支持复杂类型。
     *
     * @param xml 要解析的 XML 字符串
     * @param type 目标 Java 对象的类型引用
     * @param <T> 目标 Java 对象的类型
     * @return 解析后的 Java 对象
     * @throws RuntimeException 如果解析失败
     */
    public static <T> T parseXml(String xml, TypeReference<T> type) {
        try {
            return MAPPER.readValue(xml, type);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(String.format("解析xml失败,原文[%s]", xml), e);
        }
    }

    /**
     * 将 XML 字符串解析为 JsonNode 对象。
     *
     * @param xml 要解析的 XML 字符串
     * @return 解析后的 JsonNode 对象
     * @throws RuntimeException 如果解析失败
     */
    public static JsonNode parseXml(String xml) {
        try {
            return MAPPER.readTree(xml);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(String.format("解析xml失败,原文[%s]", xml), e);
        }
    }

    /**
     * 将 XML 字符串解析为 Map<String, Object> 对象。
     *
     * @param xml 要解析的 XML 字符串
     * @return 解析后的 Map<String, Object> 对象
     * @throws RuntimeException 如果解析失败
     */
    @SuppressWarnings(value = "unchecked")
    public static Map<String, Object> parseXml2Map(String xml) {
        try {
            return MAPPER.readValue(xml, Map.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(String.format("解析xml失败,原文[%s]", xml), e);
        }
    }

    /**
     * 将 Java 对象转换为 XML 字符串。
     *
     * @param bean 要转换的 Java 对象
     * @return 转换后的 XML 字符串，如果输入为空则返回 null
     */
    public static String toXml(Object bean) {
        return toXml(bean, null);
    }

    /**
     * 将 Java 对象转换为 XML 字符串，并指定根节点名称。
     *
     * @param bean 要转换的 Java 对象
     * @param afterRootName 指定的根节点名称
     * @return 转换后的 XML 字符串，如果输入为空则返回 null
     */
    public static String toXml(Object bean, String afterRootName) {
        if (bean == null) {
            return null;
        }
        String xml;
        try {
            xml = MAPPER.writeValueAsString(bean);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("转换为XML失败!", e);
        }
        if (StringUtil.isEmpty(afterRootName)) {
            return xml;
        }
        String beforeRootName = getXmlRootName(bean);
        if (StringUtil.isEmpty(beforeRootName)) {
            return xml;
        }
        int start = xml.startsWith(startXmlTagLeft(beforeRootName)) ? startXmlTagLeft(beforeRootName).length() : 0;
        int stop = xml.length() - (xml.endsWith(endXmlTag(beforeRootName)) ? endXmlTag(beforeRootName).length() : 0);
        return startXmlTagLeft(afterRootName) + StringUtil.substringPlus(xml, start, stop) + endXmlTag(afterRootName);
    }

    /**
     * 获取 Java 对象的 XML 根节点名称。
     *
     * @param bean Java 对象
     * @return XML 根节点名称
     */
    private static String getXmlRootName(Object bean) {
        Class<?> clz = bean.getClass();
        if (clz.isAnnotationPresent(JacksonXmlRootElement.class)) {
            JacksonXmlRootElement annotation = clz.getAnnotation(JacksonXmlRootElement.class);
            String value = annotation.localName();
            if (StringUtil.isNotEmpty(value)) {
                return value;
            }
        } else if (clz.isAnnotationPresent(JsonRootName.class)) {
            JsonRootName annotation = clz.getAnnotation(JsonRootName.class);
            String value = annotation.value();
            if (StringUtil.isNotEmpty(value)) {
                return value;
            }
        }
        return clz.getSimpleName();
    }

    /**
     * 生成 XML 开始标签的左半部分。
     *
     * @param nodeName 节点名称
     * @return XML 开始标签的左半部分
     */
    public static String startXmlTagLeft(String nodeName) {
        return "<" + nodeName;
    }

    /**
     * 生成 XML 结束标签。
     *
     * @param nodeName 节点名称
     * @return XML 结束标签
     */
    public static String endXmlTag(String nodeName) {
        return "</" + nodeName + ">";
    }
}
